#include "stdafx.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "PreferencesDialog.h"
#include "regionitem.h"
#include "RegionScene.h"
#include "undocommand.h"

class MainWindowPrivate
{
public:
	MainWindowPrivate(MainWindow* parent)	
		: settings(new QSettings())
		, curFile("")
		, maxRecentFiles(10)
		, undoGroup(new QUndoGroup(parent))
		, actionSceneGroup(new QActionGroup(parent))
	{
		for(int i = RegionBegin; i < RegionEnd; ++i)
		{
			QSharedPointer<Region> item(Region::createRegion(i));
			prototypes.append(item);
		}
	}
	
public:
	Ui::MainWindowClass ui;	
	QSettings* settings;
	QString curFile;
	int maxRecentFiles;
	QList< QSharedPointer<Region> > prototypes;
	QList<RegionScene*> scenes;
	QUndoGroup* undoGroup;
	QActionGroup* actionSceneGroup;
};


MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
	, d_ptr(new MainWindowPrivate(this))
{
	Q_D(MainWindow);
	d->ui.setupUi(this);
	setWindowTitle(qApp->applicationName());	
	setupMenuBar();
	setupToolBar();	
	// create new scene as default.
	on_actionNewScene_triggered();
}

MainWindow::~MainWindow()
{

}


 void MainWindow::setupMenuBar()
{
	Q_D(MainWindow);
	// create recent file actions
	createRecentFileActions();
	// connect undo redo action operation
	QAction* actionRedo = undoGroup()->createRedoAction(d->ui.menuEdit);
	actionRedo->setIcon(QIcon(":/MainWindow/redo.png"));
	actionRedo->setShortcutContext(Qt::ApplicationShortcut);
	actionRedo->setShortcut(QApplication::translate("MainWindowClass", "Ctrl+Y", 0, QApplication::UnicodeUTF8));
	d->ui.menuEdit->insertAction(d->ui.actionCopy,actionRedo);
	QAction* actionUndo = undoGroup()->createUndoAction(d->ui.menuEdit);
	actionUndo->setIcon(QIcon(":/MainWindow/undo.png"));
	actionUndo->setShortcutContext(Qt::ApplicationShortcut);
	actionUndo->setShortcut(QApplication::translate("MainWindowClass", "Ctrl+Z", 0, QApplication::UnicodeUTF8));
	d->ui.menuEdit->insertAction(actionRedo,actionUndo);
	d->ui.fileToolBar->addAction(actionUndo);
	d->ui.fileToolBar->addAction(actionRedo);

	connect(d->actionSceneGroup,SIGNAL(triggered(QAction*)),SLOT(sceneActionTriggered(QAction*)));
 }

void MainWindow::setupToolBar()
{
	Q_D(MainWindow);

	// setup file toolbar
	d->ui.menuNew->setDefaultAction(d->ui.actionNewScene);
	d->ui.fileToolBar->insertAction(d->ui.actionOpen,d->ui.menuNew->menuAction());
	connect(d->ui.menuNew->menuAction(),SIGNAL(triggered()),SLOT(newMenuTriggered()));
	// setup region toolbar.
	QList<QAction*> regionActions = d->ui.regionToolBar->actions();
	Q_ASSERT(regionActions.count() == d->prototypes.count());
	int index = 0;
	foreach(QAction* action, regionActions)
	{
		action->setData(QVariant::fromValue(d->prototypes[index].data()));
		++index;
	}
	connect(d->ui.regionToolBar,SIGNAL(actionTriggered(QAction*)),SLOT(regionActionTriggered(QAction*)));

	
}

void MainWindow::regionActionTriggered(QAction* action)
{
	Q_D(MainWindow);
	if(action->isChecked())
	{
		QList<QAction*> regionActions = d->ui.regionToolBar->actions();
		foreach(QAction* act, regionActions)
		{
			if(act != action && act->isChecked())
				act->setChecked(false);
		}
		QVariant value = action->data();
		Region* item = value.value<Region*>();
		d->ui.graphicsView->setPrototypeRegion(item);
	}
	else
	{
		d->ui.graphicsView->setPrototypeRegion(0);
	}
}

void MainWindow::newMenuTriggered()
{
	Q_D(MainWindow);
	QAction* action = d->ui.menuNew->defaultAction();
	action->trigger();
}

void MainWindow::sceneActionTriggered(QAction* action)
{
	Q_D(MainWindow);
	RegionScene* scene = action->data().value<RegionScene*>();
	if(scene != d->ui.graphicsView->regionScene())
	{
		if(d->ui.graphicsView->regionScene())
			d->ui.graphicsView->regionScene()->disconnect(SIGNAL(selectionChanged()));
		d->ui.graphicsView->setregionItemscene(scene);		
		connect(scene,SIGNAL(selectionChanged()),SLOT(updateRegionActions()));
		undoGroup()->setActiveStack(scene->undoStack());
	}
}

void MainWindow::updateRegionActions()
{
	Q_D(MainWindow);
	RegionScene* scene = d->ui.graphicsView->regionScene();
	Q_ASSERT(scene);
	// update action group status.
	QList<Region*> selectedregionItems = scene->selectedregionItems();
	bool enabled = selectedregionItems.count() >= 2;
	d->ui.actionGroup->setEnabled(enabled);
	// update action ungroup status.
	enabled = false;
	foreach(Region* item, selectedregionItems)
	{
		if(item->type() == Group)
		{
			enabled = true;
			break;
		}
	}
	d->ui.actionUngroup->setEnabled(enabled);

	// update action sendToBack and bringToFront status.
	enabled = selectedregionItems.count() >= 1;
	d->ui.actionSendToBack->setEnabled(enabled);
	d->ui.actionBringToFront->setEnabled(enabled);
}

 void MainWindow::createRecentFileActions()
 {
	 Q_D(MainWindow);
	d->ui.menuRecentFiles->clear();
	for (int i = 0; i < d->maxRecentFiles; ++i) 
	{
		QAction* action = new QAction(d->ui.menuRecentFiles);
		action->setVisible(false);
		d->ui.menuRecentFiles->addAction(action);         
        connect(action, SIGNAL(triggered()),this, SLOT(openRecentFile()));
    }
	updateRecentFileActions();
 }

int MainWindow::maxRecentFiles() const
{
	return d_func()->maxRecentFiles;
}

void MainWindow::setMaxRecentFiles(const int maxRecentFiles)
{
	Q_D(MainWindow);
	if(maxRecentFiles != d->maxRecentFiles)
	{
		d->maxRecentFiles = maxRecentFiles;
		createRecentFileActions();
	}
}

QString MainWindow::currentFile() const
{
	return d_func()->curFile;
}


void MainWindow::setCurrentFile(const QString &fileName)
{
	Q_D(MainWindow);
	d->curFile = fileName;
	setWindowTitle(qApp->applicationName() + " - " + fileName);
	QStringList files = d->settings->value("recentFileList").toStringList();
	files.removeAll(fileName);
	files.prepend(fileName);
	while (files.size() > d->maxRecentFiles)
		files.removeLast();

	d->settings->setValue("recentFileList", files);
	updateRecentFileActions();
}

QUndoGroup* MainWindow::undoGroup() const
{
	return d_func()->undoGroup;
}

RegionScene* MainWindow::activeregionItemscene() const
{
	return d_func()->ui.graphicsView->regionScene();
}

QUndoStack* MainWindow::activeUndoStack() const
{
	return activeregionItemscene()->undoStack();
}

 void MainWindow::updateRecentFileActions()
 {
	 Q_D(MainWindow);
     QStringList files = d->settings->value("recentFileList").toStringList();

     int numRecentFiles = qMin(files.size(), d->maxRecentFiles);

	 QList<QAction*> recentFileActs = d->ui.menuRecentFiles->actions();
     for (uint i = 0; i < numRecentFiles; ++i) 
	 {
		 QString strippedName = QFileInfo(files[i]).fileName();
         QString text = tr("&%1 %2").arg(i + 1).arg(strippedName);
         recentFileActs[i]->setText(text);
         recentFileActs[i]->setData(files[i]);
         recentFileActs[i]->setVisible(true);
     }
     for (int j = numRecentFiles; j < d->maxRecentFiles; ++j)
         recentFileActs[j]->setVisible(false);
 }

 void MainWindow::openRecentFile()
{
	QAction *action = qobject_cast<QAction *>(sender());
	loadFile(action->data().toString());
}

 void 
MainWindow::on_menuNew_triggered(QAction* action)
{
	Q_D(MainWindow);
	d->ui.menuNew->setDefaultAction(action);
	d->ui.menuNew->setIcon(action->icon());
}

void MainWindow::on_actionNewScene_triggered()
{
	Q_D(MainWindow);
	RegionScene* scene = new RegionScene(this);
	scene->setObjectName("Untitled");

	undoGroup()->addStack(scene->undoStack());

	QAction* sceneAction = d->ui.menuScene->addAction(scene->objectName());
	sceneAction->setCheckable(true);	
	sceneAction->setData(QVariant::fromValue(scene));
	d->actionSceneGroup->addAction(sceneAction);	
	sceneAction->trigger();
	
}

void MainWindow::on_actionNewFile_triggered()
{

}

void MainWindow::on_actionOpen_triggered()
{
	QString fileName = QFileDialog::getOpenFileName(this);
	if (!fileName.isEmpty())
		loadFile(fileName);
}

void MainWindow::on_actionSave_triggered()
{
	Q_D(MainWindow);
	if (currentFile().isEmpty())
		on_actionSaveAs_triggered();
	else
		saveFile(currentFile());
}

void MainWindow::on_actionSaveAs_triggered()
{
	QString fileName = QFileDialog::getSaveFileName(this);
	if (fileName.isEmpty())
		return;
	saveFile(fileName);
}

void MainWindow::on_actionImport_triggered()
{

}

void MainWindow::on_actionExport_triggered()
{

}


void MainWindow::on_actionPreferences_triggered()
{
	PreferencesDialog dialog(this);
	dialog.exec();
}


void MainWindow::on_actionAbout_triggered()
{
	
}

void MainWindow::on_actionGroup_triggered()
{
	Q_D(MainWindow);
	QList<Region*> selectedItems = activeregionItemscene()->selectedregionItems();
	activeUndoStack()->push(new RegionGroupCommand(activeregionItemscene(),selectedItems));
}

void MainWindow::on_actionUngroup_triggered()
{
	Q_D(MainWindow);
	QList<Region*> selectedItems = activeregionItemscene()->selectedregionItems();
	foreach(Region* item, selectedItems)
	{
		RegionGroup* group = qgraphicsitem_cast<RegionGroup*>(item);
		if(group)
		{
			activeUndoStack()->push(new RegionUngroupCommand(activeregionItemscene(),group));
		}
	}
}

void MainWindow::on_actionSendToBack_triggered()
{
	QList<Region*> selectedItems = activeregionItemscene()->selectedregionItems();
	activeregionItemscene()->sendRegionToBack(selectedItems);
}

void MainWindow::on_actionBringToFront_triggered()
{
	QList<Region*> selectedItems = activeregionItemscene()->selectedregionItems();
	activeregionItemscene()->bringRegionToFront(selectedItems);
}

void MainWindow::loadFile(const QString &fileName)
{
	Q_D(MainWindow);
	setCurrentFile(fileName);
	try
	{
		QFile file(fileName);
		if (!file.open(QFile::ReadOnly | QFile::Text)) 
		{
			QMessageBox::warning(this, tr("Load file"),
				tr("Cannot read file %1:\n%2.")
				.arg(fileName)
				.arg(file.errorString()));
			return;
		}
		QTextStream in(&file);
		QApplication::setOverrideCursor(Qt::WaitCursor);
		/*textEdit->setPlainText(in.readAll());*/
		QApplication::restoreOverrideCursor();


		statusBar()->showMessage(tr("File loaded"), 2000);
	}
	catch(std::exception& e)
	{
		QMessageBox::critical(this,tr("Load file"),e.what());
		return;
	}
}

void MainWindow::saveFile(const QString &fileName)
 {
	 Q_D(MainWindow);
     QFile file(fileName);
     if (!file.open(QFile::WriteOnly | QFile::Text)) {
         QMessageBox::warning(this, tr("Recent Files"),
                              tr("Cannot write file %1:\n%2.")
                              .arg(fileName)
                              .arg(file.errorString()));
         return;
     }

     QTextStream out(&file);
     QApplication::setOverrideCursor(Qt::WaitCursor);
    // out << textEdit->toPlainText();
     QApplication::restoreOverrideCursor();

     setCurrentFile(fileName);
     statusBar()->showMessage(tr("File saved"), 2000);
 }


